iT邦幫忙

2021 iThome 鐵人賽

DAY 20
0
自我挑戰組

Vue.js 從零開始系列 第 20

Vue.js 從零開始:props 元件的溝通

  • 分享至 

  • xImage
  •  

上篇component元件有說到每個元件範圍都應該是獨立的,更不應該發生子元件直接改變根元件的情況,元件與元件又該怎麼正確傳遞資料呢?


Props起手式

子元件做好之後,為了能重複使用,就會使用外部元件的資料,供傳子元件使用,但是又不能靠子元件直接取用,這時就用使用props屬性來完成。

<div id="app">
    <h4>{{ text }}</h4>
    <con-tainer :test-props="demo"></con-tainer>   
</div>

:test-props="demo",前面的:test-props內層元件,後面的"demo"外層元件,好記的方式:前內後外。

const app = Vue.createApp({
  data() {
    return {
      text: "外部元件",
      demo: "外部元件傳遞的文字"
    };
  }
});
app.component("ConTainer", {
  props: ["testProps"],
  template: `<div>
    <h4>{{ text }}</h4><h3>{{ testProps }}<h3>
  </div>`
});
app.mount("#app");

內部元件的props屬性宣告從外部引入到內部元件,並且透過外層模板的v-bind完成兩個元件的資料傳遞,HTML可以說是兩個元件溝通的橋樑。

補充:``props命名有使用駝峰命名,記得寫在模板時要改為連字號,因為HTML不分大小寫,例如:props: ["testProps"]testProps要改為test-props


props單向數據流

當內層元件想使用v-model來改變外層元件的資料時會跳出這行警告,[Vue warn]: Attempting to mutate prop "test". Props are readonly.Props是有讀取限制的。

<div id="app">
    <con-tainer :test-props="demo"></con-tainer>   
</div>
const app = Vue.createApp({
  data() {
    return {
      demo: "外部元件傳遞的文字"
    };
  }
});
app.component("ConTainer", {
  props: ["testProps"],
  template: `<div>
    <h3>{{ testProps }}<h3>
    <input type="text" v-model="testProps">
  </div>`
});
app.mount("#app");


傳入props時有v-bind與沒有v-bind的區別

觀察import-num有無綁定v-bind的差別:

<div id="app">
    <con-tainer import-num="400"></con-tainer>
    <con-tainer :import-num="num"></con-tainer>   
</div>
const app = Vue.createApp({
  data() {
    return {
      num: 500
    };
  }
});
app.component("ConTainer", {
  props: ["importNum"],
  template: `<div>
    <h3>value: {{ importNum }} </h3>
    <h3>value: {{ typeof importNum }} </h3>
  </div>`
});
app.mount("#app");

在外部元件的模板裡,未綁定v-bind的情況下,內部元件props依然可以接受資料,任何值傳入到內部元件props都會是string的型別。有綁定v-bind就會依據外部元件datanum型別,內部也會顯示該型別。


props型別驗證

多人開發有時會需要驗證外部元件props傳入的型別,這時就可以使用型別驗證的技巧,來得知適當的提示。

上面範例在內元件中props都是使用陣列方式(可以帶多個值),例如props:['one','two'],如果要進行驗證,就要改為大括號物件的形式。

準備好一個內部元件areaComponentconsole.log還不會跳出提示:

<div id="app">
    <area-component
     :pro-a="fun" :pro-b="text"
      pro-c="num" :pro-d="num">
    </area-component>
</div>
const areaComponent = {
  props: {
    proA: Function,
    //多個型別檢查
    proB: [String, Number],
    //必要值 物件形式可以設立多個條件
    proC: {
      type: String,
      required: true
    },
    //預設值
    proD: {
      type: Number,
      default: "hello"
    }
  },
  template: `{{ proA }} <br> {{ proB }} <br> {{ proC }} <br> {{ proD }}`
};
const app = Vue.createApp({
  data() {
    return {
      num: 500,
      text: "小明",
      boo: true,
      fun: () => {
        return "a";
      },
      test: 100
    };
  },
  components: {
    areaComponent
  }
});
app.mount("#app");



將上面範例程式碼內部元件:pro-a="fun"fun改為text

<div id="app">
    <area-component :pro-a="text" :pro-b="text" pro-c="num" :pro-d="num"></area-component>
</div>

此時console.log就會跳出提示:[Vue warn]: Invalid prop: type check failed for prop 'proA'. Expected Function, got String with value '小明'.

意思是預期應該是一個Function,但傳入結果卻是字串

補充

required: true:一定要給一個值,如果沒有就會跳出提示。
default: "hello":當沒有透過props傳入值,畫面就會給出hello的預設值,可以將:pro-d="num"移除看出差異在哪裡。
pro-c="num"console.log為什麼沒跳出提示?因為沒綁定v-bind,都會自動變成String型別。

codePen 完整範例

以上如有錯誤,歡迎指教

/images/emoticon/emoticon22.gif


參考資料

六角學院
重新認識 Vue.js
Vue.js


上一篇
Vue.js 從零開始:元件
下一篇
Vue.js 從零開始:emit 元件的溝通
系列文
Vue.js 從零開始30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言